"""
工具基类和注册系统

这个模块定义了工具系统的核心接口和管理机制，
展示了如何设计一个可扩展的工具架构。
"""

import asyncio
import inspect
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, Callable, Union
from dataclasses import dataclass
from enum import Enum


class ToolType(Enum):
    """工具类型枚举"""
    CALCULATION = "calculation"
    SEARCH = "search"
    FILE_OPERATION = "file_operation"
    COMMUNICATION = "communication"
    DATA_PROCESSING = "data_processing"
    SYSTEM = "system"
    CUSTOM = "custom"


@dataclass
class ToolParameter:
    """工具参数定义"""
    name: str                          # 参数名
    type: type                         # 参数类型
    description: str                   # 参数描述
    required: bool = True              # 是否必需
    default: Any = None                # 默认值
    validation: Optional[Callable] = None  # 验证函数


@dataclass 
class ToolResult:
    """工具执行结果"""
    success: bool                      # 是否成功
    result: Any = None                 # 结果数据
    error: Optional[str] = None        # 错误信息
    metadata: Optional[Dict] = None    # 元数据
    execution_time: float = 0.0        # 执行时间（秒）


class Tool(ABC):
    """
    工具基类
    
    所有工具都必须继承这个基类，实现统一的接口。
    这确保了工具系统的一致性和可扩展性。
    """
    
    def __init__(self, name: str, description: str, tool_type: ToolType = ToolType.CUSTOM):
        self.name = name
        self.description = description
        self.tool_type = tool_type
        self.parameters: List[ToolParameter] = []
        self.usage_count = 0
        self.error_count = 0
        
        # 自动从 execute 方法提取参数信息
        self._extract_parameters()
    
    def _extract_parameters(self):
        """从 execute 方法提取参数信息"""
        execute_signature = inspect.signature(self.execute)
        
        for param_name, param in execute_signature.parameters.items():
            if param_name == 'self':
                continue
                
            # 确定参数类型
            param_type = param.annotation if param.annotation != inspect.Parameter.empty else str
            
            # 确定是否必需
            required = param.default == inspect.Parameter.empty
            
            # 创建参数定义
            tool_param = ToolParameter(
                name=param_name,
                type=param_type,
                description=f"参数 {param_name}",
                required=required,
                default=param.default if not required else None
            )
            
            self.parameters.append(tool_param)
    
    @abstractmethod
    async def execute(self, **kwargs) -> Any:
        """
        执行工具功能
        
        这是工具的核心方法，子类必须实现具体的功能逻辑。
        """
        pass
    
    async def safe_execute(self, **kwargs) -> ToolResult:
        """
        安全执行工具
        
        包装 execute 方法，提供错误处理、参数验证和执行统计。
        """
        import time
        start_time = time.time()
        
        try:
            # 1. 参数验证
            validation_result = self.validate_parameters(kwargs)
            if not validation_result.success:
                self.error_count += 1
                return ToolResult(
                    success=False,
                    error=validation_result.error,
                    execution_time=time.time() - start_time
                )
            
            # 2. 执行工具
            result = await self.execute(**kwargs)
            
            # 3. 更新统计
            self.usage_count += 1
            execution_time = time.time() - start_time
            
            return ToolResult(
                success=True,
                result=result,
                execution_time=execution_time,
                metadata={
                    "tool_name": self.name,
                    "usage_count": self.usage_count
                }
            )
            
        except Exception as e:
            self.error_count += 1
            execution_time = time.time() - start_time
            
            return ToolResult(
                success=False,
                error=f"工具执行错误: {str(e)}",
                execution_time=execution_time,
                metadata={
                    "tool_name": self.name,
                    "error_count": self.error_count
                }
            )
    
    def validate_parameters(self, kwargs: Dict[str, Any]) -> ToolResult:
        """验证参数"""
        # 检查必需参数
        for param in self.parameters:
            if param.required and param.name not in kwargs:
                return ToolResult(
                    success=False,
                    error=f"缺少必需参数: {param.name}"
                )
        
        # 类型检查和自定义验证
        for param_name, value in kwargs.items():
            param_def = next((p for p in self.parameters if p.name == param_name), None)
            if param_def:
                # 类型检查
                if param_def.type != Any and not isinstance(value, param_def.type):
                    try:
                        # 尝试类型转换
                        kwargs[param_name] = param_def.type(value)
                    except (ValueError, TypeError):
                        return ToolResult(
                            success=False,
                            error=f"参数 {param_name} 类型错误，期望 {param_def.type.__name__}，得到 {type(value).__name__}"
                        )
                
                # 自定义验证
                if param_def.validation and not param_def.validation(value):
                    return ToolResult(
                        success=False,
                        error=f"参数 {param_name} 验证失败"
                    )
        
        return ToolResult(success=True)
    
    def get_schema(self) -> Dict[str, Any]:
        """获取工具模式定义"""
        return {
            "name": self.name,
            "description": self.description,
            "type": self.tool_type.value,
            "parameters": [
                {
                    "name": p.name,
                    "type": p.type.__name__,
                    "description": p.description,
                    "required": p.required,
                    "default": p.default
                }
                for p in self.parameters
            ],
            "usage_stats": {
                "usage_count": self.usage_count,
                "error_count": self.error_count,
                "error_rate": self.error_count / max(1, self.usage_count)
            }
        }
    
    def get_help(self) -> str:
        """获取工具帮助信息"""
        help_text = f"""
## 🛠️ {self.name}

**描述**: {self.description}
**类型**: {self.tool_type.value}

### 参数

"""
        
        for param in self.parameters:
            required_text = "必需" if param.required else "可选"
            default_text = f" (默认: {param.default})" if param.default is not None else ""
            
            help_text += f"- **{param.name}** ({param.type.__name__}, {required_text}): {param.description}{default_text}\n"
        
        help_text += f"""
### 使用统计

- 调用次数: {self.usage_count}
- 错误次数: {self.error_count}
- 成功率: {(self.usage_count - self.error_count) / max(1, self.usage_count) * 100:.1f}%
"""
        
        return help_text


class ToolRegistry:
    """
    工具注册表
    
    管理所有可用的工具，提供工具发现、注册和调用功能。
    这是工具系统的中央管理器。
    """
    
    def __init__(self):
        self._tools: Dict[str, Tool] = {}
        self._tool_categories: Dict[ToolType, List[str]] = {}
        
        # 注册内置工具
        self._register_built_in_tools()
    
    def _register_built_in_tools(self):
        """注册内置工具"""
        # 这里会自动注册一些基础工具
        # 具体工具的注册会在各个工具模块中完成
        pass
    
    def register(self, tool: Tool) -> bool:
        """
        注册工具
        
        将新工具添加到注册表中，使其可被 Agent 使用。
        """
        if not isinstance(tool, Tool):
            raise ValueError("必须是 Tool 类的实例")
        
        if tool.name in self._tools:
            print(f"警告: 工具 '{tool.name}' 已存在，将被覆盖")
        
        self._tools[tool.name] = tool
        
        # 按类型分类
        if tool.tool_type not in self._tool_categories:
            self._tool_categories[tool.tool_type] = []
        
        if tool.name not in self._tool_categories[tool.tool_type]:
            self._tool_categories[tool.tool_type].append(tool.name)
        
        return True
    
    def unregister(self, tool_name: str) -> bool:
        """注销工具"""
        if tool_name not in self._tools:
            return False
        
        tool = self._tools[tool_name]
        del self._tools[tool_name]
        
        # 从分类中移除
        if tool.tool_type in self._tool_categories:
            if tool_name in self._tool_categories[tool.tool_type]:
                self._tool_categories[tool.tool_type].remove(tool_name)
        
        return True
    
    def get_tool(self, tool_name: str) -> Optional[Tool]:
        """获取指定工具"""
        return self._tools.get(tool_name)
    
    def has_tool(self, tool_name: str) -> bool:
        """检查工具是否存在"""
        return tool_name in self._tools
    
    def list_tools(self, tool_type: Optional[ToolType] = None) -> List[str]:
        """列出工具"""
        if tool_type is None:
            return list(self._tools.keys())
        else:
            return self._tool_categories.get(tool_type, [])
    
    def search_tools(self, query: str) -> List[Tool]:
        """搜索工具"""
        query_lower = query.lower()
        matching_tools = []
        
        for tool in self._tools.values():
            # 搜索工具名称和描述
            if (query_lower in tool.name.lower() or 
                query_lower in tool.description.lower()):
                matching_tools.append(tool)
        
        return matching_tools
    
    async def execute_tool(self, tool_name: str, **kwargs) -> ToolResult:
        """执行工具"""
        tool = self.get_tool(tool_name)
        if not tool:
            return ToolResult(
                success=False,
                error=f"工具 '{tool_name}' 不存在"
            )
        
        return await tool.safe_execute(**kwargs)
    
    def get_registry_stats(self) -> Dict[str, Any]:
        """获取注册表统计信息"""
        total_usage = sum(tool.usage_count for tool in self._tools.values())
        total_errors = sum(tool.error_count for tool in self._tools.values())
        
        category_stats = {}
        for tool_type, tool_names in self._tool_categories.items():
            category_stats[tool_type.value] = {
                "count": len(tool_names),
                "tools": tool_names
            }
        
        return {
            "total_tools": len(self._tools),
            "total_usage": total_usage,
            "total_errors": total_errors,
            "overall_success_rate": (total_usage - total_errors) / max(1, total_usage),
            "categories": category_stats,
            "most_used_tools": sorted(
                [(name, tool.usage_count) for name, tool in self._tools.items()],
                key=lambda x: x[1],
                reverse=True
            )[:5]
        }
    
    def export_schemas(self) -> Dict[str, Any]:
        """导出所有工具的模式定义"""
        return {
            tool_name: tool.get_schema()
            for tool_name, tool in self._tools.items()
        }
    
    def import_tools_from_config(self, config: Dict[str, Any]):
        """从配置文件导入工具"""
        # 这个方法可以用于从配置文件批量注册工具
        # 实现会根据具体需求来设计
        pass


# 全局工具注册表实例
default_registry = ToolRegistry()